package com.ghck.server.service.impl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ghck.server.controller.events.RedisSyncEvent;
import com.ghck.server.dao.HospitalDictMapper;
import com.ghck.server.model.HospitalDict;
import com.ghck.server.model.query.HospitalDictQuery;
import com.ghck.server.service.HospitalDictService;
import com.ghck.server.service.RegionDictService;
import com.ghck.server.utils.IntegerUtil;
import com.ghck.server.utils.RedisKeyUtil;
import com.ghck.server.utils.SpringContextUtil;

/**
 * 医院  <br>
 * dict_hospital <br>
 * v1.0 2016-05-01
 */
@Service
@Transactional
public class HospitalDictServiceImpl implements HospitalDictService {

	private static final Logger logger = LoggerFactory.getLogger(HospitalDictServiceImpl.class);

	@Autowired
	private HospitalDictMapper hospitalDictMapper;

	@Autowired
	private RedisTemplate<String,Object> template;

	@Autowired
	RegionDictService regionDictService;

	/**
	 *根据ID删除 医院
	 */
	@Override
	public Integer deleteHospitalDictById(Integer id){
		return hospitalDictMapper.deleteById(id);
	}

	/**
	 *新增 医院
	 */
	@Override
	@Transactional
	public Integer batchInsertHospitalDict(List<? extends HospitalDict> hospitalDicts){
		Integer count = hospitalDictMapper.batchInsert(hospitalDicts);
		return count;
	}
	/**
	 *新增 医院
	 */
	@Override
	@Transactional
	public Integer insertHospitalDict(HospitalDict domain){
		hospitalDictMapper.insert(domain);
		Integer id = domain.getId();
		if(IntegerUtil.isPositiveInteger(id)){
			RedisSyncEvent event = new RedisSyncEvent(id, RedisSyncEvent.HOSPITAL);
			SpringContextUtil.getApplicationContext().publishEvent(event);
		}
		return id;
	}





	/**
	 *更新 医院
	 */
	@Override
	@Transactional
	public Integer updateHospitalDict(HospitalDict domain){
		hospitalDictMapper.update(domain);
		Integer id = domain.getId();
		if(IntegerUtil.isPositiveInteger(id)){
			RedisSyncEvent event = new RedisSyncEvent(id, RedisSyncEvent.HOSPITAL);
			SpringContextUtil.getApplicationContext().publishEvent(event);
		}
		return id;
	}

	/**
	 *根据ID查询 医院
	 */
	public HospitalDict findHospitalDictById(Integer id){
		HospitalDict result = hospitalDictMapper.findById(id);
		if(result!=null){
			result.dealWith();
		}
		return result;
	}

	/**
	 *通过query 查询 医院
	 */
	public List<HospitalDict> findHospitalDictByQuery(HospitalDictQuery query){
		query.dealWith();
		List<HospitalDict> result = hospitalDictMapper.findByQuery(query);
		if(CollectionUtils.isNotEmpty(result)) {
			Collections.sort(result);
			for (HospitalDict hospitalDict : result) {
				hospitalDict.dealWith();
			}
		}
		return result;
	}	

	/**
	 *通过query count总条数
	 */
	public Integer countHospitalDictByQuery(HospitalDictQuery query){
		query.dealWith();
		Integer result = hospitalDictMapper.countByQuery(query);
		return result;
	}

	/**
	 * 通过ids查询
	 */
	public List<HospitalDict> findHospitalDictByIds(List<Integer> ids){
		List<HospitalDict> result = hospitalDictMapper.findByIds(ids);
		if(CollectionUtils.isNotEmpty(result)) {
			for (HospitalDict hospitalDict : result) {
				hospitalDict.dealWith();
			}
		}
		return result;
	}

	/**
	 *根据name查询 身体部位
	 */
	public HospitalDict findByName(String name){
		HospitalDict result = hospitalDictMapper.findByName(name);
		if(result!=null){
			result.dealWith();
		}
		return result;
	}

	/**
	 *获取所有字典 身体部位
	 */
	public List<HospitalDict> findAll(){
		List<HospitalDict> result = hospitalDictMapper.findAll();
		if(CollectionUtils.isNotEmpty(result)) {
			for (HospitalDict hospitalDict : result) {
				hospitalDict.dealWith();
			}
		}
		return result;
	}


	public void syncInRedis(boolean force){
		String key = RedisKeyUtil.hospitalHashKey();
		if(force || (!template.hasKey(key) )){
			List<HospitalDict> result = findAll();
			Map<Integer, Set<Integer>> regionMapHospitalList = new HashMap<Integer, Set<Integer>>();
			if (CollectionUtils.isNotEmpty(result)) {
				Map<String, HospitalDict> map = new HashMap<String, HospitalDict>();
				for (HospitalDict hospitalDict : result) {
					String hashKey = RedisKeyUtil.domainIdKey(hospitalDict.getId());
					map.put(hashKey, hospitalDict);

					Integer regionId =hospitalDict.getRegionId();
					if(!regionMapHospitalList.containsKey(regionId)){
						regionMapHospitalList.put(regionId, new HashSet<>());
					}
					regionMapHospitalList.get(regionId).add(hospitalDict.getId());
				}
				if(!map.isEmpty()){
					template.delete(key);
					template.opsForHash().putAll(key, map);
//					template.expire(key, 7, TimeUnit.DAYS);
				}

				if(!regionMapHospitalList.isEmpty()){
					String regionKey = RedisKeyUtil.regionIdMapHosptialIdList();
					Map<String, List<Integer>> regionMap = new HashMap<String, List<Integer>>();
					template.delete(regionKey);
					for (Entry<Integer, Set<Integer>> entry : regionMapHospitalList.entrySet()) {
						Integer regionId = entry.getKey();
						String hashKey = RedisKeyUtil.domainIdKey(regionId);
						regionMap.put(hashKey, new ArrayList<>(entry.getValue()));
					}
					template.opsForHash().putAll(regionKey, regionMap);
//					template.expire(regionKey, 8, TimeUnit.DAYS);
				}
			}
		}
	}

	@Override
	public void syncSingletonRedis(Integer hospitalId){
		String key = RedisKeyUtil.hospitalHashKey();
		if(!template.hasKey(key)){
			syncInRedis(true);
		}else{
			HospitalDict hospitalDict = hospitalDictMapper.findById(hospitalId);
			String hashKey = RedisKeyUtil.domainIdKey(hospitalId);
			if(hospitalDict.getInUsed()==1){
				template.opsForHash().put(key, hashKey, hospitalDict);
			}else{
				template.opsForHash().delete(key, hashKey);
			}

			Integer regionId = hospitalDict.getRegionId();
			String regionKey = RedisKeyUtil.regionIdMapHosptialIdList();
			hashKey = RedisKeyUtil.domainIdKey(regionId);
			if(template.opsForHash().hasKey(regionKey, hashKey)){
				Object list = template.opsForHash().get(regionKey, hashKey);
				if(list instanceof List){
					boolean find =false;
					Object findObject = null;
					for (Object item : (List)list) {
						if(item instanceof Integer){
							if(hospitalId.intValue() == (Integer)item){
								find = true;
								findObject = item;
								break;
							}
						}
					}
					if(!find){
						if(hospitalDict.getInUsed()==1){
							((List)list).add(hospitalId);
							template.opsForHash().put(regionKey, hashKey,list);
						}
					}else{
						if(hospitalDict.getInUsed()==0){
							((List)list).remove(findObject);
							template.opsForHash().put(regionKey, hashKey,list);
						}
					}
				}
			}else if(hospitalDict.getInUsed()==1){
				List<Integer> list = new ArrayList<Integer>();
				list.add(hospitalId);
				template.opsForHash().put(regionKey, hashKey,list);
			}
		}
	}

	public List<HospitalDict> findByRegionIdsInCache(List<Integer> regionIds){
		List<HospitalDict> result = new ArrayList<>();
		String key = RedisKeyUtil.hospitalHashKey();
		if(!template.hasKey(key)){
			syncInRedis(true);
		}

		if (CollectionUtils.isNotEmpty(regionIds)) {

			String regionKey = RedisKeyUtil.regionIdMapHosptialIdList();

			List<String> keys = new ArrayList<String>();
			for (Integer regionId : regionIds) {
				String hashKey = RedisKeyUtil.domainIdKey(regionId);
				keys.add(hashKey);
			}
			List<String> hospitalHashKeys = new ArrayList<>();

			HashOperations<String, String, List<Integer>> hOperations = template.opsForHash();

			List<List<Integer>> lists = hOperations.multiGet(regionKey, keys);
			if (CollectionUtils.isNotEmpty(lists)) {
				for (List<Integer> list : lists) {
					if (CollectionUtils.isNotEmpty(list)) {
						for (Integer object : list) {
							String hospitalHashKey = RedisKeyUtil.domainIdKey(object);
							hospitalHashKeys.add(hospitalHashKey);
						}
					}
				}
			}
			HashOperations<String, String, HospitalDict> hOperations2 =  template.opsForHash();
			
			result = hOperations2.multiGet(key, hospitalHashKeys);
			if (CollectionUtils.isNotEmpty(result)) {
				for(int i=result.size()-1; i>=0; i--){
					if(!(result.get(i) instanceof HospitalDict)){
						result.remove(i);
					}
				}
			}
		}
		return result;
	}

	public List<HospitalDict> findByIdsInCache(List<Integer> ids){
		List<HospitalDict> result = new ArrayList<>();
		String key = RedisKeyUtil.hospitalHashKey();
		if(!template.hasKey(key)){
			syncInRedis(true);
		}

		List<String> hospitalHashKeys = new ArrayList<>();
		for (Integer id : ids) {
			String hospitalHashKey = RedisKeyUtil.domainIdKey(id);
			hospitalHashKeys.add(hospitalHashKey);
		}

		HashOperations<String, String, HospitalDict> hOperations2 =  template.opsForHash();
		
		result = hOperations2.multiGet(key, hospitalHashKeys);
		if (CollectionUtils.isNotEmpty(result)) {
			for(int i=result.size()-1; i>=0; i--){
				if(!(result.get(i) instanceof HospitalDict)){
					result.remove(i);
				}
			}
		}
		return result;
	}

	public HospitalDict findByIdInCache(Integer id){
		String key = RedisKeyUtil.hospitalHashKey();
		if(!template.hasKey(key)){
			syncInRedis(true);
		}
		String hashKey =  RedisKeyUtil.domainIdKey(id);
		Object object = template.opsForHash().get(key, hashKey);
		if(object instanceof HospitalDict){
			return (HospitalDict) object;
		}
		return null;
	}
}	